#include <iostream>
#include <functional>

#include "Unit.hpp"
#include "GameManager.hpp"
#include "UnitManager.hpp"

#include "Debug.hpp"

CGameManager::CGameManager() : initialized(false)
{
	try
	{
		if(!Initialize())
			throw;
	}
	catch(const std::exception &ex)
	{
		std::cout << "Caught: " << ex.what() << std::endl;
	}
}

CGameManager::~CGameManager()
{
	delete unitManager;
	//delete mediaManager;
}

bool CGameManager::Initialize()
{
	unitManager = new CUnitManager();
	//mediaManager = new CMediaManager();

	char* vertSrc = nullptr;
	char* fragSrc = nullptr;

	//CTimer timerA;
	double diff;

	//timeA = timerA.to_double(timerA.diff_largeint());
	//cout << "took " << timeA << "ms to initialize." << endl;

	//timerA.start();

	for(int32_t i = 0; i < 8; ++i)
	{
		auto player = unitManager->CreatePlayer(string("player"), PlayerClass::WIZARD, PlayerSex::MALE);

		for(int32_t j = 0; j < 32; j++)
		{
			auto item = unitManager->InitItem(1, ItemClass::SMALLTRINKET);

			item->isIdentified = 1;
			unitManager->CreateUnitStat(item, StatId::STAT_HEALTH, 10);
			if(!unitManager->AddLink(item))
				throw;

		//	item = unitManager->AddInventoryItem<Unit<UnitPlayer>>(player, item);
			//unitManager->UpdateVector().push(&item);
		}
		//unitManager->UpdateVector().push(&player);
	}

#if 0
	for(int32_t i = 0; i < 1024; i++)
	{
		auto monster = unitManager->InitMonster(1);

		if(!unitManager->AddLink(monster))
		{
			unitManager->DestroyUnit(monster);
			throw;
		}

		for(int32_t j = 0; j < 2; j++)
		{
			auto item = unitManager->InitItem(1, SMALLTRINKET);

			item.itemData->isIdentified = 1;
			CreateUnitStat(item, STAT_HEALTH, 10);

			if(!unitManager->AddLink(item))
			{
				unitManager->DestroyUnit(item);
				throw;
			}

			item = unitManager->AddInventoryItem(monster, item);
			//unitManager->UpdateVector().push(&item);
		}
		unitManager->UpdateVector().push(&monster);
	}

	for(int32_t i = 0; i < 1024; i++)
	{
		auto object = unitManager->InitObject();

		if(!unitManager->AddLink(object))
		{
			unitManager->DestroyUnit(object);
			throw;
		}

	}
#endif

	//cout << "unitMap size is " << unitManager->GetPlayerMap<UNIT_TYPE_PLAYER>().size() << endl;
	//cout << "Update vector size is " << unitManager->UpdateVector().size() << endl;

	states.push(bind(&CGameManager::RunGame, this));

	initialized = true;

	return true;
}

bool CGameManager::Run()
{
	while(states.size())
	{
		if(!states.top()(this))
			return false;
	}

	return true;
}

void CGameManager::Shutdown()
{
	while(states.size())
		states.pop();
}

bool CGameManager::RunMenu()
{
	states.pop();

	states.push(bind(&CGameManager::RunGame, this));

	return true;
}

bool CGameManager::RunGame()
{
	//static CTimer timerB;
	//static LARGE_INTEGER timeA = { 0 };
	//static LARGE_INTEGER timeB = { 0 };

	static double A, B, diff;
	static int i = 0;

	//A = timerB.getCount<double>(&timeA);

	//double next_game_tick = 0.0;
	//static DWORD stick = GetTickCount();
	//stick = next_game_tick = GetTickCount();
	//double stick =  timerB.gettime<double>();
	//DWORD stick = GetTickCount();
	//int loops = 0;

	if(!unitManager->UpdateUnits())
	{
		states.pop();
		return false;
	}

	//B = timerB.getCount<double>(&timeB);
	diff = B - A;
	++i;
	if(diff >= 0.000999)
		cout << "Iteration " << i << " took " << diff << "secs." << endl;

	//auto foundUnit = unitManager->FindLink<UNIT_TYPE_PLAYER>((uint32_t)1);
	//if(foundUnit)
	//	cout << (*foundUnit)->unitName << " HP: " << statManager->CalcStat(**foundUnit, STAT_HEALTH) << endl;

	return true;
}
